using System;
using System.Collections.Generic;
using System.Text;

using NHibernate;
using NHibernate.Criterion;
using Spring.Data.NHibernate.Generic.Support;

using QLTDK.DataAccess.Interfaces.Base;
using QLTDK.Entities.Base;

namespace QLTDK.DataAccess.Base
{
    public abstract class NHibernateDao<T, IdT> : HibernateDaoSupport, IGenericDao<T, IdT> where T : EntityObject<IdT>
    {
        #region Declarations

        // Default maxResults was used by the methods that dont have maxResult parameter
        private readonly int defaultMaxResults;

        #endregion

        #region Constructor

        public NHibernateDao()
        {
            defaultMaxResults = 100;
        }

        #endregion
		
        #region Methods
	
        #region IGenericDao<T,IdT> Members
		
        public virtual T GetById(IdT id)
        {
            return HibernateTemplate.Get<T>(id);
        }
        public IList<T> GetAll()
        {
            return GetAll(defaultMaxResults);
        }

        public IList<T> GetAll(int maxResults)
        {
            HibernateTemplate.MaxResults = maxResults;
            return HibernateTemplate.LoadAll<T>();
        }

        public virtual IList<T> FindAll(T exampleInstance, params string[] propertiesToExclude)
        {
            return FindAll(exampleInstance, defaultMaxResults, propertiesToExclude);
            
        }

        public virtual IList<T> FindAll(T exampleInstance, int maxResults, params string[] propertiesToExclude)
        {
            return HibernateTemplate.ExecuteFind<T>(
                delegate(ISession session)
                {
                    ICriteria criteria = session.CreateCriteria(typeof(T));
                    Example example = Example.Create(exampleInstance);

                    foreach (string propertyToExclude in propertiesToExclude)
                    {
                        example.ExcludeProperty(propertyToExclude);
                    }

                    criteria.Add(example);
                    criteria.SetMaxResults(maxResults);

                    return criteria.List<T>();
                });

        }

        public virtual T FindOne(T exampleInstance, params string[] propertiesToExclude)
        {
            IList<T> foundList = FindAll(exampleInstance, propertiesToExclude);

            if (foundList.Count > 1)
            {
                throw new NonUniqueResultException(foundList.Count);
            }
            else if (foundList.Count == 1)
            {
                return foundList[0];
            }

            return default(T);
        }

        public virtual T Save(T entity)
        {
            HibernateTemplate.Save(entity);
            return entity;
        }

        public virtual T SaveOrUpdate(T entity)
        {
            HibernateTemplate.SaveOrUpdate(entity);
            return entity;
        }

        public virtual void Delete(T entity)
        {
            HibernateTemplate.Delete(entity);
        }

        public virtual T Update(T entity)
        {
            HibernateTemplate.Update(entity);
            return entity;
        }

        #endregion

        #endregion

    }
}

